package com.ruoyi.quartz.serviece.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.constant.ScheduleConstants;
import com.ruoyi.common.exception.TaskException;
import com.ruoyi.quartz.CronUtils;
import com.ruoyi.quartz.ScheduleUtils;
import com.ruoyi.quartz.entity.SysJob;
import com.ruoyi.quartz.mapper.SysJobMapper;
import com.ruoyi.quartz.serviece.ISysJobService;
import lombok.AllArgsConstructor;
import net.dreamlu.mica.mybatis.service.impl.MicaServiceImpl;
import org.quartz.JobDataMap;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.util.List;

/**
 * 定时任务调度表 业务层实现类
 *
 * @author dy
 */
@Service
@AllArgsConstructor
public class SysJobServiceImpl extends MicaServiceImpl<SysJobMapper, SysJob> implements ISysJobService {

    private final Scheduler scheduler;

    private final SysJobMapper sysJobMapper;

    /**
     * 项目启动时，初始化定时器 主要是防止手动修改数据库导致未同步到定时任务处理（注：不能手动修改数据库ID和任务组名，否则会导致脏数据）
     */
    @PostConstruct
    public void init() throws SchedulerException, TaskException {
        scheduler.clear();
        List<SysJob> jobList = sysJobMapper.selectList(new LambdaQueryWrapper<>());
        for (SysJob job : jobList) {
            ScheduleUtils.createScheduleJob(scheduler, job);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean insertJob(SysJob sysJob) throws TaskException, SchedulerException {
        sysJob.setStatus(ScheduleConstants.Status.PAUSE.getValue());
        int rows = sysJobMapper.insert(sysJob);
        if (rows > 0) {
            ScheduleUtils.createScheduleJob(scheduler, sysJob);
        }
        return rows > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateJob(SysJob sysJob) throws TaskException, SchedulerException {
        SysJob properties = sysJobMapper.selectById(sysJob.getId());
        if (properties != null) {
            sysJobMapper.updateById(sysJob);
            // 判断是否存在
            JobKey jobKey = ScheduleUtils.getJobKey(sysJob.getId(), sysJob.getJobGroup());
            if (scheduler.checkExists(jobKey)) {
                // 防止创建时存在数据问题 先移除，然后在执行创建操作
                scheduler.deleteJob(jobKey);
            }
            ScheduleUtils.createScheduleJob(scheduler, sysJob);
            return true;
        }
        return false;
    }

    @Override
    public boolean changeStatus(SysJob sysJob) throws SchedulerException {
        if (ScheduleConstants.Status.NORMAL.getValue().equals(sysJob.getStatus())) {
            sysJobMapper.updateById(sysJob);
            scheduler.resumeJob(ScheduleUtils.getJobKey(sysJob.getId(), sysJob.getJobGroup()));
            return true;
        } else if (ScheduleConstants.Status.PAUSE.getValue().equals(sysJob.getStatus())) {
            sysJobMapper.updateById(sysJob);
            scheduler.pauseJob(ScheduleUtils.getJobKey(sysJob.getId(), sysJob.getJobGroup()));
            return true;
        }
        return false;
    }

    @Override
    public boolean run(SysJob job) throws SchedulerException {
        Long jobId = job.getId();
        String jobGroup = job.getJobGroup();
        SysJob properties = sysJobMapper.selectById(job.getId());
        if (properties != null) {
            // 参数
            JobDataMap dataMap = new JobDataMap();
            dataMap.put(ScheduleConstants.TASK_PROPERTIES, properties);
            scheduler.triggerJob(ScheduleUtils.getJobKey(jobId, jobGroup), dataMap);
            return true;
        }
        return false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteJobByIds(Long[] ids) throws SchedulerException {
        for (Long jobId : ids) {
            SysJob job = sysJobMapper.selectById(jobId);
            if (job != null) {
                deleteJob(job);
            }
        }
        return true;
    }

    /**
     * 删除任务后，所对应的trigger也将被删除
     *
     * @param job 调度信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteJob(SysJob job) throws SchedulerException {
        Long jobId = job.getId();
        String jobGroup = job.getJobGroup();
        int rows = sysJobMapper.deleteById(jobId);
        if (rows > 0) {
            scheduler.deleteJob(ScheduleUtils.getJobKey(jobId, jobGroup));
        }
        return rows > 0;
    }

    /**
     * 校验cron表达式是否有效
     *
     * @param cronExpression 表达式
     * @return 结果
     */
    @Override
    public boolean checkCronExpressionIsValid(String cronExpression) {
        return CronUtils.isValid(cronExpression);
    }

}